<?php if (!defined('CORE_DIR')) die('Wrong entry point!');

/* 
 * Copyright 2010 Anton Muraviev a.k.a kuromaisu
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 */

Aero::define('DatabaseLayerSpecification', AS_SINGLETON);

/*
 * SpecificationLibarySpecification
 */
class DatabaseLayerSpecification extends AeroSpec
{
	protected function initialize()
	{
		Aero::import('db/base/driver');
		
		Aero::setOption('database.default', array(
			'driver' => 'specs/db/MockDBDriver',
			'server' => 'http://localhost',
			'username' => 'foo',
			'password' => 'bar',
			'database' => 'focus_pocus'
		));
		
		Aero::setOption('database.test', array(
			'driver' => 'specs/db/MockDBDriver',
			'server' => 'http://localhost',
			'username' => 'foo2',
			'password' => 'bar2',
			'database' => 'focus_pocus'
		));
	}
	
	protected function itShouldEstablishDBConnection()
	{
		$db = AeroDatabase::connect(); // default connection
		$db2 = AeroDatabase::connect('test'); // test connection (using MockDBDriver)
		$db3 = AeroDatabase::connect('test');
		
		$this->object($db)->isInstanceOf('MockDBDriver');
		$this->object($db2)->references($db3);
		$this->object($db)->doesNotReference($db2);
	}
	
	protected function itShouldCorrectlyParseAndReplaceQueryTokens()
	{
		$db = AeroDatabase::connect();
		
		// Basic query to make sure it works at all ;-)
		$db->query('SELECT * FROM funk');
		$this->string($db->sql)->equals('SELECT * FROM funk');
		
		// Escaping parameters
		$db->query('SELECT * FROM funk WHERE foo = {foo} AND bar = {bar} AND focus = {focus}',
			array('foo' => true,'bar' => 23,'focus' => 'pocus'));
		$this->string($db->sql)->equals('SELECT * FROM funk WHERE foo = 1 AND bar = 23 AND focus = "pocus"');
		
		// Typical UPDATE query
		$db->query('UPDATE funk SET {keys=values} WHERE id = {id}',
			array('id' => 23),
			array('foo' => true,'bar' => 23,'focus' => 'pocus'));
		$this->string($db->sql)->equals('UPDATE funk SET `foo` = 1, `bar` = 23, `focus` = "pocus" WHERE id = 23');
		
		// Typical INSERT query
		$db->query('INSERT INTO funk ({keys}) VALUES ({values})',
			array(),
			array('funk . foo' => true,'bar' => 23,'focus' => 'poc\'us'));
		$this->string($db->sql)->equals('INSERT INTO funk (`funk`.`foo`, `bar`, `focus`) VALUES (1, 23, "poc\\\'us")');
		
		// Typical INSERT query with raw parameter
		$db->query('INSERT INTO funk ({keys}, `now`) VALUES ({values}, NOW())',
			array(),
			array('foo' => true,'bar' => 23,'focus' => 'poc\'us'));
		$this->string($db->sql)->equals('INSERT INTO funk (`foo`, `bar`, `focus`, `now`) VALUES (1, 23, "poc\\\'us", NOW())');
	}
	
	protected function itShouldWrapQueryResultInCustomObject()
	{
		$db = Aero::load('specs/db/MockDBDriver');
		
		$result = $db->query('SELECT * FROM funk');
		
		$this->object($result)->isInstanceOf('MockDBResult');
		$this->value($result->count())->equals(100);
				
		$this->value($obj_0 = $result->fetch())->is('object');
		$this->value($result->fetch('assoc'))->is('array');
		$this->value($result->fetch('array'))->is('array');
		
		$result->seek(0);
		$obj_1 = $result->fetch();
		$result->reset();
		$obj_2 = $result->fetch();
		
		$this->object($obj_1)->isIdenticalTo($obj_0);
		$this->object($obj_1)->isIdenticalTo($obj_2);
		
		$result->seek(5);
		$obj_3 = $result->fetch();
		
		$hash = $result->keysAndValues('foo','bar');
		
		$result->seek(5);
		$obj_4 = $result->fetch();
		
		$this->object($obj_3)->isIdenticalTo($obj_4);
		$this->value($hash[$obj_3->foo])->isIdenticalTo($obj_3->bar);
		$this->value(count($hash))->equals($result->count());
		$this->object($obj_1)->isNotEqualTo($obj_3);
		
		$result->seek(4);
		$obj_5 = $result->fetch();
		$obj_6 = $result->fetch();
		
		$this->object($obj_3)->isIdenticalTo($obj_6);
		
		$result->reset();
		
		$i = 0;
		
		while ($row = $result->fetch())
		{
			$i++;
		}
		
		$this->value($i)->equals($result->count());
	}
}